﻿using System;
using System.Collections.Generic;
using System.Linq;
using FileSecurityManager.BizEntities;
using FileSecurityManager.DataAccess.Exceptions;
using FileSecurityManager.DataAccess.Interfaces;

namespace FileSecurityManager.DataAccess.Repositories
{
    public class UserLinq2SqlRepository : Linq2SqlRepository, IUserRepository
    {
        #region IRepository implementation
        /// <summary>
        /// Creates the specified model.
        /// </summary>
        /// <param name="model">The model.</param>
        /// <returns>Item model</returns>
        public UserModel Create(UserModel model)
        {
            UserModel userModel;

            if (model == null)
            {
                throw new DataAccessException(
                    "User repository could not create user model.",
                    new NullReferenceException("The 'model' parameter is null."));
            }

            var isUserExist = (from user in FSMDatabase.Users where user.UserName == model.UserName select user).Count() >
                              0;
            if (!isUserExist)
            {
                User newUser = model.ToEntity(FSMDatabase);
                try
                {
                    FSMDatabase.Users.InsertOnSubmit(newUser);
                    FSMDatabase.SubmitChanges();
                }
                catch (Exception ex)
                {
                    throw new DataAccessException(
                        string.Format(
                            "User repository could not save user model to FSM database.{0}.", ex.Message),
                        ex);
                }

                userModel = newUser.ToModel(FSMDatabase);

                if (userModel != null)
                {
                    Log.DebugFormat("User model was created with id = {0}.", userModel.ItemId);
                }

                return userModel;
            }
            return null;
            //throw new DataAccessException(String.Format("User with userName {0} already exists in database.", model.UserName));
        }

        /// <summary>
        /// Gets the model by id.
        /// </summary>
        /// <param name="id">The identifier.</param>
        /// <returns>Item model</returns>
        public UserModel GetById(int id)
        {
            throw new NotImplementedException();
        }

        /// <summary>
        /// Gets model by name.
        /// </summary>
        /// <param name="name">The user name.</param>
        /// <returns>The user model</returns>
        public UserModel GetByName(string name)
        {
            try
            {
                var user =
                    (from dbUser in FSMDatabase.Users where dbUser.UserName == name select dbUser).FirstOrDefault().ToModel(FSMDatabase);
                return user;
            }
            catch (Exception ex)
            {
                var errorMsg = string.Format("Error retrieving user by userName: {0}. Error: {1}", name, ex.Message);
                Log.Error(errorMsg, ex);
                throw new DataAccessException(errorMsg, ex);
            }
        }

        /// <summary>
        /// Updates the specified model.
        /// </summary>
        /// <param name="model">The model.</param>
        public void Update(UserModel model)
        {
            if (model == null)
            {
                var errorMsg =
                    string.Format("User repository could not update user model.The \'model\' parameter is null.");
                Log.Error(errorMsg);

                throw new DataAccessException(
                    "User repository could not update user model.",
                    new NullReferenceException("The 'model' parameter is null."));
            }

            try
            {
                User searchedUser =
                    (from dbUser in FSMDatabase.Users
                     where dbUser.Id == model.ItemId
                     select dbUser).FirstOrDefault();
                searchedUser.FromModel(model, this.FSMDatabase);
            }
            catch (ArgumentNullException ex)
            {
                var errorMsg = string.Format("User repository could not update user model with id = {0}", model.ItemId);
                Log.Error(errorMsg, ex);
                throw new DataAccessException(errorMsg, ex);
            }

            try
            {
                FSMDatabase.SubmitChanges();
            }
            catch (Exception ex)
            {
                var errorMsg =
                    string.Format(
                        "User repository could not save user model with id = {0} to FSMStorage database.{1}",
                        model.ItemId,
                        ex.Message);
                Log.Error(errorMsg, ex);

                throw new DataAccessException(errorMsg, ex);
            }

            Log.DebugFormat("User model was updated with id = {0}", model.ItemId);
        }

        /// <summary>
        /// Deletes the specified id.
        /// </summary>
        /// <param name="id">The identifier.</param>
        public void Delete(int id)
        {
            if (id < 0)
            {
                throw new DataAccessException(
                    string.Format("User repository could not delete user model with id = {0}.", id),
                    new ArgumentException("The 'id' parameter is < 0."));
            }

            int saCount =
                (from dbUser in FSMDatabase.Users where dbUser.UserRole.Role.RoleName == "SuperAdmin" select dbUser).
                    Count();

            var user = (from dbUser in FSMDatabase.Users where dbUser.Id == id select dbUser).FirstOrDefault();

            if (user != null)
            {
                try
                {
                    bool isSuperAdmin = user.UserRole.Role.RoleName == "SuperAdmin";

                    if (isSuperAdmin && saCount < 2)
                    {
                        return;
                    }

                    if (user.UserRole != null)
                    {
                        FSMDatabase.UserRoles.DeleteOnSubmit(user.UserRole);
                    }
                    if (user.UserOption != null)
                    {
                        FSMDatabase.UserOptions.DeleteOnSubmit(user.UserOption);
                    }
                    
                    FSMDatabase.Users.DeleteOnSubmit(user);
                    FSMDatabase.SubmitChanges();
                }
                catch (Exception ex)
                {
                    throw new DataAccessException(
                        string.Format(
                            "User repository could not delete user model {0} from FSMStorage database.{1}.", id, ex.Message),
                        ex);
                }

                Log.DebugFormat("User model with id = {0} was successfully deleted.", id);
            }
        }

        /// <summary>
        /// Gets all models.
        /// </summary>
        /// <returns>All models list</returns>
        public List<UserModel> GetAll()
        {
            try
            {
                var users =
                    (from dbUser in this.FSMDatabase.Users select dbUser.ToModel(this.FSMDatabase)).ToList();

                return users;
            }
            catch (Exception ex)
            {
                var errorMsg = string.Format("Error retrieving users: {0}", ex.Message);
                Log.Error(errorMsg, ex);
                throw new DataAccessException(errorMsg, ex);
            }
        }
        #endregion

        #region IUserRepository implementation

        /// <summary>
        /// Gets the users by role.
        /// </summary>
        /// <param name="roleModel">The role model.</param>
        /// <returns>Users according to role</returns>
        public List<UserModel> GetUsersByRole(RoleModel roleModel)
        {
            throw new NotImplementedException();
        }

        /// <summary>
        /// Deletes the user role.
        /// </summary>
        /// <param name="userName">Name of the user.</param>
        public void DeleteUserRole(string userName)
        {
            throw new NotImplementedException();
        }
        #endregion
    }
}
